﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace AppMain
{
    public class BaseScene : IEquatable<BaseScene>
    {
        public Dictionary<long, IRole> map = new Dictionary<long, IRole>();
        public long uid;
        public long sceneId;
        private string sceneName;
        private float bornPosX = 0;
        private float bornPosY = 0;
        private float bornPosZ = 0;
        public Segment[] colliderSegments = new Segment[] { new Segment() };

        private bool IsSoleScene
        {
            get
            {
                return uid == sceneId;
            }
        }

        private void createCollider()
        {
            //sql查询
            string sceneSql = string.Format("select *from tb_scene_temp where id='{0}'", this.sceneId);
            var Reader = SqlMgr.Instance.select(sceneSql);
            if (Reader.Read())
            {
                bornPosX = (float)Reader[2];
                bornPosY = (float)Reader[3];
                bornPosZ = (float)Reader[4];
                sceneName = (string)Reader[5];
            }
            Reader.Close();
            //查询场景碰撞
            string selectRoleSql = string.Format("select *from tb_scene_collider_temp where sceneName='{0}'", sceneName);
            var roleReader = SqlMgr.Instance.select(selectRoleSql);
            List<Segment> lst = new List<Segment>();
            while (roleReader.Read())
            {
                Segment segment = new Segment();
                segment.startX = (float)roleReader[3];
                segment.startZ = (float)roleReader[4];
                segment.endX = (float)roleReader[5];
                segment.endZ = (float)roleReader[6];
                lst.Add(segment);
            }
            roleReader.Close();
            colliderSegments = lst.ToArray();
        }

        public virtual void initialize()
        {
            createCollider();
            createMonster();
            createTrigger();
        }

        void createTrigger()
        {
            //创建一个触发器实体
            IAttrMap attrMap = new RoleAttrMap();
            attrMap.changeAttr<long>(RoleAttr.RoleId, MathUtils.UniqueLID);
            attrMap.changeAttr(RoleAttr.NickName, "trigger");
            attrMap.changeAttr(RoleAttr.SceneId, sceneId);
            attrMap.changeAttr(RoleAttr.Speed, 6f);
            attrMap.changeAttr(RoleAttr.RoleType, RoleType.Trigger);
            attrMap.changeAttr(RoleAttr.RoleTempId, 1001);
            attrMap.changeAttr(RoleAttr.LookFlag, 1);
            attrMap.changeAttr<float>(RoleAttr.AttackSpeed, 1f);
            attrMap.changeAttr(RoleAttr.Scene, this);
            TriggerEntity role = new TriggerEntity(attrMap);
            role.box3D.updatePos(this.sceneId == 101002 ? 5.84F : 3F, 0, -1.42F);
            RoleMgr.Instance.addRole(role);
            map.Add(role.UID, role);
        }

        void createMonster()
        {
            //创建一个monster实体
            IAttrMap attrMap = new RoleAttrMap();
            attrMap.changeAttr<long>(RoleAttr.RoleId, MathUtils.UniqueLID);
            attrMap.changeAttr(RoleAttr.NickName, "小型牛头人");
            attrMap.changeAttr(RoleAttr.SceneId, sceneId);
            attrMap.changeAttr(RoleAttr.Speed, 6f);
            attrMap.changeAttr(RoleAttr.RoleType, RoleType.Monster);
            attrMap.changeAttr(RoleAttr.RoleTempId, 2);
            attrMap.changeAttr(RoleAttr.Level, 24);
            attrMap.changeAttr(RoleAttr.MaxHp, 500000);
            attrMap.changeAttr(RoleAttr.NowHp, 500000);
            attrMap.changeAttr(RoleAttr.LookFlag, 1);
            attrMap.changeAttr<float>(RoleAttr.AttackSpeed, 1f);
            attrMap.changeAttr(RoleAttr.Scene, this);
            Monster role = new Monster(attrMap);
            role.box3D.updatePos(this.sceneId == 101002 ? -4F : 3F, 0, -2.2F);
            RoleMgr.Instance.addRole(role);
            map.Add(role.UID, role);
        }


        List<IRole> removeLst = new List<IRole>();
        public void tick(float frameTime)
        {
            //add
            while (addQueue.Count > 0)
            {
                IRole role = addQueue.Dequeue();
                addToMap(role);
            }

            //tick
            removeLst.Clear();
            var ier = map.GetEnumerator();
            while (ier.MoveNext())
            {
                IRole role = ier.Current.Value;
                if (role.CanRemove)
                {
                    removeLst.Add(role);
                }
                else
                {
                    role.tick(frameTime);
                }
            }
            //remove
            if (removeLst.Count > 0)
            {
                for (int i = 0; i < removeLst.Count; i++)
                {
                    IRole role = removeLst[i];
                    this.removeRole(role);
                }
            }
        }

        public void removeRole(IRole role)
        {
            //从当前场景移除玩家 
            map.Remove(role.UID);
            role.dispose();
            pb.RoleLeaveBroadCastMsg msg = new pb.RoleLeaveBroadCastMsg();
            msg.roleId = role.UID;
            broadCast(Cmd.RoleLeaveBroadCastMsg, msg);
            Console.WriteLine(string.Format("移除玩家:{0} 广播", role.UID));
        }
        public void removeRole(long roleId)
        {
            IRole role;
            if (map.TryGetValue(roleId, out role))
            {
                removeRole(role);
            }
        }

        Queue<IRole> addQueue = new Queue<IRole>();
        public void addRole(IRole role)
        {
            addQueue.Enqueue(role);
        }

        private void addToMap(IRole role)
        {
            if (!map.ContainsKey(role.UID))
            {
                role.AttrMap.changeAttr(RoleAttr.SceneId, this.sceneId);
                if (!IsSoleScene)
                {
                    role.AttrMap.changeAttr(RoleAttr.CopySceneUID, this.uid);
                }
                map.Add(role.UID, role);
                role.AttrMap.changeAttr(RoleAttr.Scene, this);
                Console.WriteLine(string.Format("玩家真实进入场景 roleId:{0}  sceneId:{1} ", role.UID, this.sceneId));

                //广播给线上的人
                broadCastOnLinePlayer(role);
                //广播线上的人给当前实体
                broadCastBeforeRoles(role);
            }
            else
            {
                Logger.logError("场景重复添加了实体" + this.sceneId);
            }
        }

        void broadCastOnLinePlayer(IRole baseRole)
        {
            BoxRole role = baseRole as BoxRole;
            int roleType = role.AttrMap.getAttr<int>(RoleAttr.RoleType).Value;
            if (roleType < RoleType.MaxRole)
            {
                pb.RoleEnterBroadCastMsg msg = new pb.RoleEnterBroadCastMsg();
                msg.roleId = role.UID;
                msg.roleType = role.AttrMap.getAttr<int>(RoleAttr.RoleType).Value;
                msg.roleTempId = role.AttrMap.getAttr<int>(RoleAttr.RoleTempId).Value;
                msg.roleName = role.AttrMap.getAttr<string>(RoleAttr.NickName).Value;
                msg.roleLevel = role.AttrMap.getAttr<int>(RoleAttr.Level).Value;
                DynamicBox3D box3d = role.box3D;
                msg.posx = box3d.posX;
                msg.posy = box3d.posY;
                msg.posz = box3d.posZ;
                msg.lookFlag = role.AttrMap.getAttr<int>(RoleAttr.LookFlag).Value;
                msg.maxHp = role.AttrMap.getAttr<int>(RoleAttr.MaxHp).Value;
                msg.nowHp = role.AttrMap.getAttr<int>(RoleAttr.NowHp).Value;
                msg.attackSpeed = role.AttrMap.getAttr<float>(RoleAttr.AttackSpeed).Value;
                //把新加入的玩家广播给已经在线的人
                broadCastIgnoreRole(Cmd.RoleEnterBroadCastMsg, msg, role.UID);
            }
            else if (roleType < RoleType.MaxBullet)
            {
                pb.BulletMsg msg = new pb.BulletMsg();
                msg.sourceId = role.AttrMap.getAttr<long>(RoleAttr.MasterId).Value;
                msg.tempId = role.AttrMap.getAttr<int>(RoleAttr.RoleTempId).Value;
                msg.uid = (int)role.AttrMap.getAttr<long>(RoleAttr.RoleId).Value;
                msg.pos = new pb.PBVector3();
                msg.pos.x = role.box3D.posX;
                msg.pos.y = role.box3D.posY;
                msg.pos.z = role.box3D.posZ;
                Vec3 dir = role.AttrMap.getAttr<Vec3>(RoleAttr.Dir).Value;
                msg.dir = new pb.PBVector3();
                msg.dir.x = dir.x;
                msg.dir.y = dir.y;
                msg.dir.z = dir.z;
                //广播client
                broadCast(Cmd.BulletMsg, msg);
            }
            else if (roleType < RoleType.MaxTrap)
            {

            }

        }

        public void broadCastIgnoreRole(short cmd, object obj, long roleId)
        {
            var ier = map.GetEnumerator();
            while (ier.MoveNext())
            {
                NetRole netRole = ier.Current.Value as NetRole;
                if (roleId != ier.Current.Value.UID && netRole != null)
                {
                    netRole.send(cmd, obj);
                    Console.WriteLine(string.Format("把玩家:{0}同步给:{1}", roleId, ier.Current.Value.UID));
                }
            }
        }

        private void broadCastBeforeRoles(IRole currRole)
        {
            NetRole netRole = currRole as NetRole;
            if (netRole == null)
                return;
            var ier = map.GetEnumerator();
            while (ier.MoveNext())
            {
                IRole role = ier.Current.Value;
                if (currRole.UID != role.UID)
                {
                    sendRoleToRole(netRole, role);
                }
            }
        }

        void sendRoleToRole(NetRole sender, IRole needSendRole)
        {
            BoxRole role = needSendRole as BoxRole;
            int roleType = role.AttrMap.getAttr<int>(RoleAttr.RoleType).Value;
            if (roleType < RoleType.MaxRole)
            {
                pb.RoleEnterBroadCastMsg msg = new pb.RoleEnterBroadCastMsg();
                msg.roleId = role.UID;
                msg.roleType = role.AttrMap.getAttr<int>(RoleAttr.RoleType).Value;
                msg.roleTempId = role.AttrMap.getAttr<int>(RoleAttr.RoleTempId).Value;
                msg.roleName = role.AttrMap.getAttr<string>(RoleAttr.NickName).Value;
                msg.roleLevel = role.AttrMap.getAttr<int>(RoleAttr.Level).Value;
                DynamicBox3D box3d = role.box3D;
                msg.posx = box3d.posX;
                msg.posy = box3d.posY;
                msg.posz = box3d.posZ;
                msg.lookFlag = role.AttrMap.getAttr<int>(RoleAttr.LookFlag).Value;
                msg.maxHp = role.AttrMap.getAttr<int>(RoleAttr.MaxHp).Value;
                msg.nowHp = role.AttrMap.getAttr<int>(RoleAttr.NowHp).Value;
                msg.attackSpeed = role.AttrMap.getAttr<float>(RoleAttr.AttackSpeed).Value;
                //把新加入的玩家广播给已经在线的人
                sender.send(Cmd.RoleEnterBroadCastMsg, msg);
            }
            else if (roleType < RoleType.MaxBullet)
            {
                pb.BulletMsg msg = new pb.BulletMsg();
                msg.sourceId = role.AttrMap.getAttr<long>(RoleAttr.MasterId).Value;
                msg.tempId = role.AttrMap.getAttr<int>(RoleAttr.RoleTempId).Value;
                msg.uid = (int)role.AttrMap.getAttr<long>(RoleAttr.RoleId).Value;
                msg.pos = new pb.PBVector3();
                msg.pos.x = role.box3D.posX;
                msg.pos.y = role.box3D.posY;
                msg.pos.z = role.box3D.posZ;
                Vec3 dir = role.AttrMap.getAttr<Vec3>(RoleAttr.Dir).Value;
                msg.dir = new pb.PBVector3();
                msg.dir.x = dir.x;
                msg.dir.y = dir.y;
                msg.dir.z = dir.z;
                //广播client
                sender.send(Cmd.BulletMsg, msg);
            }
            else if (roleType < RoleType.MaxTrap)
            {

            }
        }

        public void broadCast(short cmd, object obj)
        {
            var ier = map.GetEnumerator();
            while (ier.MoveNext())
            {
                NetRole netRole = ier.Current.Value as NetRole;
                if (netRole != null)
                {
                    netRole.send(cmd, obj);
                }
            }
        }

        public void dispose()
        {

        }

        public bool Equals([AllowNull] BaseScene other)
        {
            return other.uid == this.uid;
        }
    }

}
